{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 导入数据，获取events"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "#保存数据\n",
    "import cPickle\n",
    "\n",
    "import itertools\n",
    "\n",
    "#处理事件字符串\n",
    "import datetime\n",
    "\n",
    "import numpy as np\n",
    "import scipy.io as sio\n",
    "import scipy.sparse as ss\n",
    "\n",
    "#相似度/距离\n",
    "import scipy.spatial.distance as ssd\n",
    "\n",
    "from collections import defaultdict\n",
    "from sklearn.preprocessing import normalize\n",
    "\n",
    "\n",
    "#导入必要的工具包\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "from sklearn.cluster import MiniBatchKMeans\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn import metrics\n",
    "\n",
    "from sklearn.decomposition import PCA\n",
    "import time\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "number4 of uniqueUsers :3391\n",
      "number4 of uniqueEvents :13418\n"
     ]
    }
   ],
   "source": [
    " \"\"\"\n",
    "我们只关心train和test中出现的user和event，因此重点处理这部分关联数据\n",
    "\n",
    "train.csv 有6列：\n",
    "user：用户ID\n",
    "event：活动ID\n",
    "invited：是否被邀请（0/1）\n",
    "timestamp：ISO-8601 UTC格式时间字符串，表示用户看到该活动的时间\n",
    "interested, and not_interested\n",
    "\n",
    "Test.csv 除了没有interested, and not_interested，其余列与train相同\n",
    " \"\"\"\n",
    "    \n",
    "# 统计训练集中有多少不同的用户的events\n",
    "uniqueUsers = set()\n",
    "uniqueEvents = set()\n",
    "\n",
    "#倒排表\n",
    "#统计每个用户参加的活动   / 每个活动参加的用户\n",
    "eventsForUser = defaultdict(set)\n",
    "usersForEvent = defaultdict(set)\n",
    "    #\n",
    "for filename in [\"train.csv\", \"test.csv\"]:\n",
    "    f = open(filename, 'rb')\n",
    "    \n",
    "    #忽略第一行（列名字）\n",
    "    f.readline()\n",
    "    for line in f:    #对每条记录\n",
    "        cols = line.strip().split(\",\")\n",
    "        uniqueUsers.add(cols[0])   #第一列为用户ID\n",
    "        uniqueEvents.add(cols[1])   #第二列为活动ID\n",
    "        \n",
    "        #eventsForUser[cols[0]].add(cols[1])    #该用户参加了这个活动\n",
    "        #usersForEvent[cols[1]].add(cols[0])    #该活动被用户参加\n",
    "    f.close()\n",
    "\n",
    "\n",
    "n_uniqueUsers = len(uniqueUsers)\n",
    "n_uniqueEvents = len(uniqueEvents)\n",
    "\n",
    "print(\"number4 of uniqueUsers :%d\" % n_uniqueUsers)\n",
    "print(\"number4 of uniqueEvents :%d\" % n_uniqueEvents)\n",
    "\n",
    "#用户关系矩阵表，可用于后续LFM/SVD++处理的输入\n",
    "#这是一个稀疏矩阵，记录用户对活动感兴趣\n",
    "userEventScores = ss.dok_matrix((n_uniqueUsers, n_uniqueEvents))\n",
    "userIndex = dict()\n",
    "eventIndex = dict()\n",
    "\n",
    "#重新编码用户索引字典\n",
    "for i, u in enumerate(uniqueUsers):\n",
    "    userIndex[u] = i\n",
    "    \n",
    "    \n",
    "#重新编码活动索引字典    \n",
    "for i, e in enumerate(uniqueEvents):\n",
    "    eventIndex[e] = i \n",
    "\n",
    "n_records = 0\n",
    "ftrain = open(\"train.csv\", 'rb')\n",
    "ftrain.readline()\n",
    "for line in ftrain:\n",
    "    cols = line.strip().split(\",\")\n",
    "    i = userIndex[cols[0]]  #用户\n",
    "    j = eventIndex[cols[1]] #活动\n",
    "    \n",
    "    eventsForUser[i].add(j)    #该用户参加了这个活动\n",
    "    usersForEvent[j].add(i)    #该活动被用户参加\n",
    "        \n",
    "    #userEventScores[i, j] = int(cols[4]) - int(cols[5])   #interested - not_interested\n",
    "    score = int(cols[4])\n",
    "    #if score == 0:  #0在稀疏矩阵中表示该元素不存在，因此借用-1表示interested=0\n",
    "    #userEventScores[i, j] = -1\n",
    "    #else:\n",
    "    userEventScores[i, j] = score\n",
    "ftrain.close()\n",
    "\n",
    "  \n",
    "##统计每个用户参加的活动，后续用于将用户朋友参加的活动影响到用户\n",
    "cPickle.dump(eventsForUser, open(\"PE_eventsForUser.pkl\", 'wb'))\n",
    "##统计活动参加的用户\n",
    "cPickle.dump(usersForEvent, open(\"PE_usersForEvent.pkl\", 'wb'))\n",
    "\n",
    "#保存用户-活动关系矩阵R，以备后用\n",
    "sio.mmwrite(\"PE_userEventScores\", userEventScores)\n",
    "\n",
    "\n",
    "#保存用户索引表\n",
    "cPickle.dump(userIndex, open(\"PE_userIndex.pkl\", 'wb'))\n",
    "#保存活动索引表\n",
    "cPickle.dump(eventIndex, open(\"PE_eventIndex.pkl\", 'wb'))\n",
    "\n",
    "    \n",
    "# 为了防止不必要的计算，我们找出来所有关联的用户 或者 关联的event\n",
    "# 所谓的关联用户，指的是至少在同一个event上有行为的用户pair\n",
    "# 关联的event指的是至少同一个user有行为的event pair\n",
    "uniqueUserPairs = set()\n",
    "uniqueEventPairs = set()\n",
    "for event in uniqueEvents:\n",
    "    i = eventIndex[event]\n",
    "    users = usersForEvent[i]\n",
    "    if len(users) > 2:\n",
    "        uniqueUserPairs.update(itertools.combinations(users, 2))\n",
    "        \n",
    "for user in uniqueUsers:\n",
    "    u = userIndex[user]\n",
    "    events = eventsForUser[u]\n",
    "    if len(events) > 2:\n",
    "        uniqueEventPairs.update(itertools.combinations(events, 2))\n",
    " \n",
    "#保存用户-事件关系对索引表\n",
    "cPickle.dump(uniqueUserPairs, open(\"FE_uniqueUserPairs.pkl\", 'wb'))\n",
    "cPickle.dump(uniqueEventPairs, open(\"PE_uniqueEventPairs.pkl\", 'wb'))\n",
    "\n",
    "\n",
    "\n",
    "#uniqueEventPairs\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('total events :', 13418)\n"
     ]
    }
   ],
   "source": [
    "myEventIndex = cPickle.load(open(\"PE_eventIndex.pkl\",'rb'))\n",
    "\n",
    "n_events = len(myEventIndex)\n",
    "\n",
    "print(\"total events :\",n_events)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 对筛选出的events根据词频重新编码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<13418x101 sparse matrix of type '<type 'numpy.float64'>'\n",
       "\twith 199855 stored elements in Dictionary Of Keys format>"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fin = open(\"events.csv\",'rb')\n",
    "fin.readline()#跳过第一行\n",
    "#词频特征\n",
    "eventContMatrix = ss.dok_matrix((n_events,101))\n",
    "\n",
    "for line in fin.readlines():\n",
    "    cols = line.strip().split(\",\")\n",
    "    eventId = str(cols[0])\n",
    "    \n",
    "    if eventIndex.has_key(eventId):\n",
    "        i = eventIndex[eventId]        \n",
    "        #词频\n",
    "        for j in range(9,110):\n",
    "            eventContMatrix[i,j-9] = cols[j]\n",
    "            \n",
    "fin.close()\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 聚类函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 一个参数点（聚类数据为K）的模型，在校验集上评价聚类算法性能\n",
    "def K_cluster_analysis(K, df):\n",
    "    start = time.time()\n",
    "    \n",
    "    print(\"K-means begin with clusters: {}\".format(K));\n",
    "    \n",
    "    #K-means,在训练集上训练\n",
    "    mb_kmeans = MiniBatchKMeans(n_clusters = K)\n",
    "    mb_kmeans.fit(df)\n",
    "    \n",
    "    # 在训练集和测试集上测试\n",
    "    #y_train_pred = mb_kmeans.fit_predict(X_train)\n",
    "   # y_val_pred = mb_kmeans.predict(X_val)\n",
    "    \n",
    "    #以前两维特征打印训练数据的分类结果\n",
    "    #plt.scatter(X_train[:, 0], X_train[:, 1], c=y_pred)\n",
    "    #plt.show()\n",
    "\n",
    "    # K值的评估标准\n",
    "    #常见的方法有轮廓系数Silhouette Coefficient和Calinski-Harabasz Index\n",
    "    #这两个分数值越大则聚类效果越好\n",
    "    #CH_score = metrics.calinski_harabaz_score(X_train,mb_kmeans.predict(X_train))\n",
    "    CH_score = metrics.silhouette_score(df,mb_kmeans.predict(df))\n",
    "    \n",
    "    end = time.time()\n",
    "    print(\"CH_score: {}, time elaps:{}\".format(CH_score, int(end-start)))  \n",
    "    return CH_score"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 设置超参数（聚类数目K）搜索范围"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "K-means begin with clusters: 10\n",
      "CH_score: 0.381806504732, time elaps:34\n",
      "K-means begin with clusters: 20\n",
      "CH_score: 0.27116054256, time elaps:39\n",
      "K-means begin with clusters: 30\n",
      "CH_score: 0.203279132703, time elaps:35\n",
      "K-means begin with clusters: 40\n",
      "CH_score: 0.130324032494, time elaps:36\n",
      "K-means begin with clusters: 50\n",
      "CH_score: 0.132788928668, time elaps:39\n",
      "K-means begin with clusters: 60\n",
      "CH_score: 0.109941423007, time elaps:36\n"
     ]
    }
   ],
   "source": [
    "\n",
    "Ks = [10, 20, 30,40,50,60]\n",
    "CH_scores = []\n",
    "v_scores = []\n",
    "for K in Ks:\n",
    "    ch = K_cluster_analysis(K,eventContMatrix)\n",
    "    CH_scores.append(ch)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x118a9e10>]"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\nRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x8af1898>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 绘制不同PCA维数下模型的性能，找到最佳模型／参数（分数最高）\n",
    "plt.plot(Ks, np.array(CH_scores), 'b-')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
